package org.x4ut15m.xwebshell.explorer.controller;

import com.google.gson.Gson;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.scene.control.*;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import org.x4ut15m.xwebshell.explorer.file.FileItem;
import org.x4ut15m.xwebshell.explorer.file.FileManager;
import org.x4ut15m.xwebshell.explorer.file.FileTreeItem;
import org.x4ut15m.xwebshell.sdk.controller.AbstractShellController;
import org.x4ut15m.xwebshell.sdk.controller.IController;
import org.x4ut15m.xwebshell.sdk.session.ISession;
import org.x4ut15m.xwebshell.sdk.webshell.IWebshellItem;

import java.nio.file.Paths;
import java.util.HashMap;
import java.util.LinkedHashMap;

public class FileManagerController implements IController {
    @FXML
    private Tab fileManagerTab;
    @FXML
    private AnchorPane anchorPane;
    @FXML
    private BorderPane borderPane;
    @FXML
    private HBox topHboxPane;
    // 文件目录
    @FXML
    private TreeView<FileItem> pathTreeView;
    // 文件列表
    @FXML
    private TableView<FileTreeItem> fileTableView;
    // 刷新按钮
    @FXML
    private Button refreshButton;
    @FXML
    private Button userHomeButton;
    @FXML
    private Button projectHomeButton;
    @FXML
    private Button parentPathButton;
    // 显示当前路径的文本框
    @FXML
    private TextField currentPath;
    @FXML
    private TableColumn<IWebshellItem, String> fileNameColumn;
    @FXML
    private TableColumn<IWebshellItem, Long> fileSizeColumn;
    @FXML
    private TableColumn<IWebshellItem, String> fileTypeColumn;
    @FXML
    private TableColumn<IWebshellItem, String> modifyTimeColumn;

    private String projectRootPath;
    private String userHomePath;
    private ISession webshellSession;
    private IWebshellItem webshellItem;
    private AbstractShellController shellController;
    private FileManager manager;
    private Gson gson = new Gson();
    private FileTreeItem rootPlaceHolder;
    private ClassLoader classLoader;

    @Override
    public void loadAllSubModule() {
        initFileTableView();
        tryToGetProjectRootPath();
        manager = new FileManager(projectRootPath, webshellSession, webshellItem, classLoader);
        manager.init();
        initPathTreeView();

    }

    public void initFileTableView() {
        fileNameColumn.setCellValueFactory(new PropertyValueFactory<>("fileName"));
        fileSizeColumn.setCellValueFactory(new PropertyValueFactory<>("size"));
        fileTypeColumn.setCellValueFactory(new PropertyValueFactory<>("fileType"));
        modifyTimeColumn.setCellValueFactory(new PropertyValueFactory<>("lastModified"));
    }

    public void initPathTreeView() {
        LinkedHashMap<String, FileTreeItem> rootPaths = manager.getRootPaths();

        if (!rootPaths.isEmpty()) {

            if (rootPaths.size() > 1) {
                pathTreeView.setShowRoot(false); // 不显示根节点
                rootPlaceHolder = new FileTreeItem(new FileItem("", "", ""));
                for (String root : rootPaths.keySet()) {
                    FileTreeItem rootItem = rootPaths.get(root);
                    FileItem fileItem = rootItem.getFileItem();
                    rootPlaceHolder.getChildren().add(rootItem);
                    if (!fileItem.getSubFiles().isEmpty()) {
                        for (FileItem subFile : fileItem.getSubFiles()) {
                            if (subFile.isDirectory()) {
                                rootItem.getChildren().add(new FileTreeItem(subFile));
                            }
                        }
                    }
                }
            } else {
                for (String root : rootPaths.keySet()) {
                    FileTreeItem rootItem = rootPaths.get(root);
                    rootPlaceHolder = rootItem;
                    FileItem fileItem = rootItem.getFileItem();
                    if (!fileItem.getSubFiles().isEmpty()) {
                        for (FileItem subFile : fileItem.getSubFiles()) {
                            if (subFile.isDirectory()) {
                                rootPlaceHolder.getChildren().add(new FileTreeItem(subFile));
                            }
                        }
                    }
                }
            }

            pathTreeView.setRoot(rootPlaceHolder);

        }

    }

    @Override
    public void createEventHandlerOnComponents() {
        currentPath.setOnKeyPressed(event -> {
            switch (event.getCode()) {
                case ENTER:
                    String path = currentPath.getText().trim();
                    if (!"".equals(path)) {
                        fileTableView.setItems(manager.refreshFile(path));
                    }
                    break;
                case TAB:
                    event.consume();
                    break;
                default:
                    break;
            }
        });
        refreshButton.setOnMouseClicked(event -> {
            String path = currentPath.getText().trim();
            if (!"".equals(path)) {
                fileTableView.setItems(manager.refreshFile(path));
            }
        });
        projectHomeButton.setOnMouseClicked(event -> {
            ObservableList<FileTreeItem> fileTreeItems = manager.listFile(projectRootPath);
            fileTableView.setItems(fileTreeItems);
            currentPath.setText(projectRootPath);
        });

        userHomeButton.setOnMouseClicked(event -> {
            ObservableList<FileTreeItem> fileTreeItems = manager.listFile(userHomePath);
            fileTableView.setItems(fileTreeItems);
            currentPath.setText(userHomePath);
        });
        parentPathButton.setOnMouseClicked(event -> {
            String current = ensureEndWithSlash(currentPath.getText().trim());
            String parent = ensureEndWithSlash(Paths.get(current + "../").normalize().toString());
            ObservableList<FileTreeItem> dataFromCache = null;
            if (!"".equals(current)) {
                dataFromCache = manager.getDataFromCache(parent);
                if (dataFromCache == null || dataFromCache.isEmpty()) {
                    dataFromCache = manager.listFile(parent);
                }
                fileTableView.setItems(dataFromCache);
                currentPath.setText(parent);
            }


        });
        pathTreeView.setOnMouseClicked(event -> {
            if (isDubbleClick(event)) {
                FileTreeItem selectedItem = (FileTreeItem) pathTreeView.getSelectionModel().getSelectedItem();
                if (selectedItem != null && (!selectedItem.isExpanded() || rootPlaceHolder.equals(selectedItem))) {
                    String path = getAbsolutePathBySelect(selectedItem);

                    ObservableList<FileTreeItem> observableList = manager.listFile(path);
                    if (observableList != null) {
                        fileTableView.setItems(observableList);

                    }
                    currentPath.setText(path);
                    updatePathTree(selectedItem, observableList);
                }
            }

        });

        fileTableView.setOnMouseClicked(event -> {
            if (isDubbleClick(event)) {
                FileTreeItem fileTreeItem = fileTableView.getSelectionModel().getSelectedItem();
                FileItem selectedItem = fileTreeItem.getFileItem();
                if (selectedItem != null) {
                    if (selectedItem.isDirectory()) {
                        ObservableList<FileTreeItem> dataFromCache = manager.getDataFromCache(selectedItem.getAbsolutePath());
                        if (dataFromCache == null) {
                            dataFromCache = manager.listFile(selectedItem.getAbsolutePath());
                        }
                        fileTableView.setItems(dataFromCache);
                        currentPath.setText(selectedItem.getAbsolutePath());
                        pathTreeView.getSelectionModel().select(fileTreeItem);
                        updatePathTree(fileTreeItem, dataFromCache);
                    }
                }
            }
        });

    }

    public void updatePathTree(FileTreeItem treeItem, ObservableList<FileTreeItem> observableList) {
        if (treeItem == null) {
            return;
        }
        ObservableList<TreeItem<FileItem>> children = treeItem.getChildren();
        if (treeItem.getValue().isDirectory()) {
            if (observableList.size() > 0) {
                children.clear();
            }

            for (FileTreeItem fileItem : observableList) {
                if (fileItem.getFileItem().isDirectory()) {
                    children.add(fileItem);
                }
            }
        }
    }


    public String getAbsolutePathBySelect(TreeItem<FileItem> treeItem) {
        if (treeItem == null) {
            return "";
        }

        return treeItem.getValue().getAbsolutePath();
    }

    @Override
    public void show() {

    }

    @Override
    public void close() {

    }

    public void setWebshellSession(ISession webshellSession) {
        this.webshellSession = webshellSession;
    }

    public void setWebshellItem(IWebshellItem webshellItem) {
        this.webshellItem = webshellItem;
    }

    public void setShellController(AbstractShellController shellController) {
        this.shellController = shellController;
    }

    public Tab getFileManagerTab() {
        return fileManagerTab;
    }

    public void tryToGetProjectRootPath() {
        if (shellController != null) {
            HashMap<String, String> attributeFromPlugin = (HashMap<String, String>) shellController.getAttributeFromPlugin("information", "allProperties");
            if (attributeFromPlugin != null) {
                projectRootPath = attributeFromPlugin.get("user.dir") != null ? ensureEndWithSlash(attributeFromPlugin.get("user.dir")) : "";
                userHomePath = attributeFromPlugin.get("user.home") != null ? ensureEndWithSlash(attributeFromPlugin.get("user.home")) : "";

            }
        } else {
            projectRootPath = ensureEndWithSlash(System.getProperty("user.dir"));
            userHomePath = ensureEndWithSlash(System.getProperty("user.home"));
        }

    }


    public boolean isDubbleClick(MouseEvent event) {
        return event.getClickCount() == 2;
    }

    public String ensureEndWithSlash(String path) {
        if ("".equals(path) || path == null) {
            return "";
        }
        if (path.endsWith("/")) {
            return path;
        }
        path += "/";

        return path;
    }

    public void setClassLoader(ClassLoader classLoader) {
        this.classLoader = classLoader;
    }

    public ClassLoader getClassLoader() {
        return classLoader;
    }
}


